import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_carplay/flutter_carplay.dart';
import 'package:flutter_carplay/helpers/carplay_helper.dart';
import 'package:flutter_carplay/helpers/enum_utils.dart';
import 'package:flutter_carplay/models/alert/alert_action.dart';
import 'package:flutter_carplay/models/base_tab_bar_template.dart';
import 'package:flutter_carplay/models/button/bar_button.dart';
import 'package:flutter_carplay/models/grid/grid_button.dart';
import 'package:flutter_carplay/models/grid/grid_template.dart';
import 'package:flutter_carplay/models/list/list_template.dart';
import 'package:flutter_carplay/models/playing/now_playing_btn.dart';
import 'package:flutter_carplay/models/playing/now_playing_template.dart';
import 'package:flutter_carplay/models/tabbar/tabbar_template.dart';
import 'package:flutter_carplay/constants/private_constants.dart';

/// [FlutterCarPlayController] is an root object in order to control and communication
/// system with the Apple CarPlay and native functions.
class FlutterCarPlayController {
  static final FlutterCarplayHelper _carplayHelper = FlutterCarplayHelper();
  static final MethodChannel _methodChannel =
      MethodChannel(_carplayHelper.makeFCPChannelId());
  static final EventChannel _eventChannel =
      EventChannel(_carplayHelper.makeFCPChannelId(event: "/event"));

  /// [CPTabBarTemplate], [CPGridTemplate], [CPListTemplate] in a List
  static List<dynamic> templateHistory = [];

  /// [CPTabBarTemplate], [CPGridTemplate], [CPListTemplate]
  static dynamic currentRootTemplate;

  /// [CPAlertTemplate], [CPActionSheetTemplate]
  static dynamic currentPresentTemplate;

  /// [CPNowPlayingTemplate]
  static dynamic currentNowPlayingTemplate;

  MethodChannel get methodChannel {
    return _methodChannel;
  }

  EventChannel get eventChannel {
    return _eventChannel;
  }

  Future<bool> reactToNativeModule(FCPChannelTypes type, dynamic data) async {
    final value = await _methodChannel.invokeMethod(
        CPEnumUtils.stringFromEnum(type.toString()), data);
    return value;
  }

  static void updateCPListItem(CPListItem updatedListItem) {
    _methodChannel.invokeMethod('updateListItem',
        <String, dynamic>{...updatedListItem.toJson()}).then((value) {
      if (value) {
        l1:
        for (var h in templateHistory) {
          switch (h.runtimeType) {
            case CPTabBarTemplate:
              for (var t in (h as CPTabBarTemplate).templates) {
                if (t.runtimeType.toString() == "CPListTemplate") {
                  for (var s in (t as CPListTemplate).sections) {
                    for (var i in s.items) {
                      if (i.uniqueId == updatedListItem.uniqueId) {
                        currentRootTemplate!
                            .templates[
                                currentRootTemplate!.templates.indexOf(t)]
                            .sections[t.sections.indexOf(s)]
                            .items[s.items.indexOf(i)] = updatedListItem;
                        break l1;
                      }
                    }
                  }
                }
              }
              break;
            case CPListTemplate:
              for (var s in (h as CPListTemplate).sections) {
                for (var i in s.items) {
                  if (i.uniqueId == updatedListItem.uniqueId) {
                    currentRootTemplate!
                        .sections[currentRootTemplate!.sections.indexOf(s)]
                        .items[s.items.indexOf(i)] = updatedListItem;
                    break l1;
                  }
                }
              }
              break;
            default:
          }
        }
      }
    });
  }

  static void updateListTemplate(CPListTemplate updatedListItem) {
    _methodChannel.invokeMethod('updateListTemplate',
        <String, dynamic>{...updatedListItem.toJson()}).then((value) {
      if (!value) {
        return;
      }
      bool isChange = false;
      l1:
      switch (currentRootTemplate.runtimeType) {
        case CPTabBarTemplate:
          for (var temp in currentRootTemplate.templates) {
            if (temp.runtimeType == CPListTemplate &&
                temp.uniqueId == updatedListItem.uniqueId) {
              currentRootTemplate!
                      .templates[currentRootTemplate!.templates.indexOf(temp)] =
                  updatedListItem;
              isChange = true;
              break l1;
            }
          }
          break;
        case CPListTemplate:
          if (currentRootTemplate.uniqueId == updatedListItem.uniqueId) {
            currentRootTemplate = updatedListItem;
            isChange = true;
          }
          break;
      }

      if (isChange) {
        return;
      }

      l1:
      for (var h in templateHistory) {
        if (h.runtimeType == CPListTemplate) {
          if (h.runtimeType == CPListTemplate &&
              h.uniqueId == updatedListItem.uniqueId) {
            templateHistory[templateHistory.indexOf(h)] = updatedListItem;
            isChange = true;
            break l1;
          }
        }
      }
    });
  }

  void addTemplateToHistory(dynamic template) {
    if (template.runtimeType == CPTabBarTemplate ||
        template.runtimeType == CPGridTemplate ||
        template.runtimeType == CPListTemplate) {
      templateHistory.add(template);
    } else {
      throw TypeError();
    }
  }

  void setNowPlayTemplate(CPNowPlayingTemplate template) {
    currentNowPlayingTemplate = template;
  }

  void processFCPListItemSelectedChannel(String elementId) {
    CPListItem? listItem = _carplayHelper.findCPListItem(
      templates: templateHistory,
      elementId: elementId,
    );
    if (listItem != null) {
      listItem.onPress!(
        () => reactToNativeModule(
          FCPChannelTypes.onFCPListItemSelectedComplete,
          listItem.uniqueId,
        ),
        listItem,
      );
    }
  }

  void processFCPAlertActionPressed(String elementId) {
    CPAlertAction selectedAlertAction = currentPresentTemplate!.actions
        .firstWhere((e) => e.uniqueId == elementId);
    selectedAlertAction.onPress();
  }

  void processFCPAlertTemplateCompleted(bool completed) {
    if (currentPresentTemplate?.onPresent != null) {
      currentPresentTemplate!.onPresent!(completed);
    }
  }

  void processFCPGridButtonPressed(String elementId) {
    CPGridButton? gridButton;
    l1:
    for (var t in templateHistory) {
      if (t.runtimeType.toString() == "CPGridTemplate") {
        for (var b in t.buttons) {
          if (b.uniqueId == elementId) {
            gridButton = b;
            break l1;
          }
        }
      }
    }
    if (gridButton != null) {
      gridButton.onPress();
    } else {
      debugPrint(" error:grid按键返回错误 elementId=" + elementId);
      for (var temp in templateHistory) {
        debugPrint(" error:历史窗口 ${temp.runtimeType} elementId=${temp.uniqueId}");
      }
    }
  }

  void processFCPBarButtonPressed(String elementId) {
    CPBarButton? barButton;
    var t = templateHistory.last;
    if (t.runtimeType.toString() == "CPListTemplate") {
      if (t.backButton.uniqueId == elementId) {
        barButton = t.backButton;
      }
    }

    if (barButton != null) {
      barButton.onPress();
    } else {
      debugPrint(" error:${t.runtimeType} 回调返回错误 elementId=${elementId}");
      if (t.runtimeType.toString() == "CPListTemplate") {
        debugPrint(" error:backButton.uniqueId=${t.backButton.uniqueId}");
      }
      for (var temp in templateHistory) {
        debugPrint(" error:历史窗口 ${temp.runtimeType} elementId=${temp.uniqueId}");
      }
    }
  }

  void processNowPlayingBtnPressed(String elementId) {
    CPNowPlayingTemplate? playingTemp = currentNowPlayingTemplate;
    if (playingTemp != null) {
      if ("UpNext" == elementId &&
          playingTemp.nowPlayingTemplateUpNextButtonTapped != null) {
        playingTemp.nowPlayingTemplateUpNextButtonTapped!();
      } else if ("AlbumArtist" == elementId &&
          playingTemp.nowPlayingTemplateAlbumArtistButtonTapped != null) {
        playingTemp.nowPlayingTemplateAlbumArtistButtonTapped!();
      } else {
        if (playingTemp.buttons != null) {
          CPNowPlayingButton? btn;
          l1:
          for (var b in playingTemp.buttons!) {
            if (b.uniqueId == elementId) {
              btn = b;
              break l1;
            }
          }
          if (btn != null) {
            btn.onPress();
          } else {
            debugPrint(" error:播放按键错误 elementId=${elementId}");
            for (var btn in playingTemp.buttons!) {
              debugPrint(" error:播放按键 ${btn.type} elementId=${btn.uniqueId}");
            }
          }
        }
      }
    }
  }

  void tabBarTemplate(String elementId) {
    if (currentRootTemplate == null) {
      debugPrint(" error:选择当前carplay tab错误，currentRootTemplate == null");
      return;
    }
    for (BaseTabBarTemplate temp in currentRootTemplate.templates) {
      if (temp.selectThis != null) {
        temp.selectThis!(temp.uniqueId == elementId);
      }
    }
  }
}
